﻿/// <reference path="../Core.ts" />

module Supernova {

    export class LobbyUI implements UI.ISwitchableUI {

        layout = {
            rootPanel: {
                left: 140, right: 140, top: 50, bottom: 0,
                controls: {
                    welcomeTitle: {
                        top: 0, width: 550, height: 20,
                        text: 'Supernova Multiplayer Lobby'
                    },
                    player1Label: {
                        top: 50, width: 550, height: 20,
                        text: 'Player 1: Not connected'
                    },
                    player2Label: {
                        top: 70, width: 550, height: 20,
                        text: 'Player 2: Not connected'
                    },
                    player3Label: {
                        top: 90, width: 550, height: 20,
                        text: 'Player 3: Not connected'
                    },
                    player4Label: {
                        top: 110, width: 550, height: 20,
                        text: 'Player 4: Not connected'
                    },
                    player5Label: {
                        top: 130, width: 550, height: 20,
                        text: 'Player 5: Not connected'
                    },
                    player6Label: {
                        top: 150, width: 550, height: 20,
                        text: 'Player 6: Not connected'
                    },
                    player7Label: {
                        top: 170, width: 550, height: 20,
                        text: 'Player 7: Not connected'
                    },
                    player8Label: {
                        top: 190, width: 550, height: 20,
                        text: 'Player 8: Not connected'
                    },
                    specifyNamePanel: {
                        top: 230, width: 550, bottom: 0,
                        visible: false,
                        controls: {
                            enterNameLabel: {
                                left: 0, top: 0, width: 100, height: 30,
                                text: 'Enter a name:'
                            },
                            nameTextBox: {
                                left: 110, top: 0, right: 0, height: 30,
                                text: 'Admiral'
                            },
                            joinButton: {
                                right: 0, top: 40, width: 140, height: 30,
                                text: 'Join Game',
                                onClick: this.handleJoinButtonClick
                            },
                            askForReplaysButton: {
                                right: 0, top: 80, width: 140, height: 30,
                                text: 'Replays',
                                onClick: this.askForReplaysButtonClick
                            },
                            disconnectBeforeLoginButton: {
                                right: 0, top: 120, width: 140, height: 30,
                                text: 'Disconnect',
                                onClick: this.handleDisconnectButtonClick
                            }
                        }
                    },
                    configurationPanel: {
                        top: 230, width: 550, bottom: 0,
                        visible: false,
                        controls: {
                            generatorLabel: {
                                left: 0, top: 0, width: 120, height: 25,
                                text: 'Generator:'
                            },
                            generatorComboBox: {
                                left: 120, top: 0, right: 0, height: 25,
                                onSelectedItemChanged: this.handleConfigurationChanged
                            },
                            galaxySizeLabel: {
                                left: 0, top: 32, width: 120, height: 25,
                                text: 'Galaxy Size:'
                            },
                            galaxySizeComboBox: {
                                left: 120, top: 32, right: 0, height: 25,
                                onSelectedItemChanged: this.handleConfigurationChanged
                            },
                            resourcesLabel: {
                                left: 0, top: 64, width: 120, height: 25,
                                text: 'Resources:'
                            },
                            resourcesComboBox: {
                                left: 120, top: 64, right: 0, height: 25,
                                onSelectedItemChanged: this.handleConfigurationChanged
                            },
                            traitsLabel: {
                                left: 0, top: 96, width: 120, height: 25,
                                text: 'Traits:'
                            },
                            traitsComboBox: {
                                left: 120, top: 96, right: 80, height: 25,
                                onSelectedItemChanged: this.handleConfigurationChanged
                            },
                            selectTraitsButton: {
                                right: 0, top: 96, width: 70, height: 25,
                                enabled: false,
                                text: 'Select',
                                onClick: this.handleSelectTraitsButtonClicked
                            },
                            goodiesCheckBox: {
                                left: 120, top: 128, right: 0, height: 25,
                                text: 'Goodies',
                                onCheckedChanged: this.handleConfigurationChanged
                            },
                            wrecksCheckBox: {
                                left: 120, top: 160, right: 0, height: 25,
                                text: 'Wrecks',
                                onCheckedChanged: this.handleConfigurationChanged
                            },
                            readyButton: {
                                left: 0, top: 200, width: 140, height: 30,
                                enabled: false,
                                text: 'Ready',
                                onClick: this.handleReadyButtonClick
                            },
                            notReadyButton: {
                                left: 150, top: 200, width: 140, height: 30,
                                enabled: false,
                                text: 'Not Ready',
                                onClick: this.handleNotReadyButtonClick
                            },
                            disconnectAfterLoginButton: {
                                left: 300, top: 200, width: 140, height: 30,
                                text: 'Disconnect',
                                onClick: this.handleDisconnectButtonClick
                            }
                        }
                    },
                    traitsPanel: {
                        top: 230, width: 550, bottom: 0,
                        visible: false,
                        controls: {
                            backToConfigurationButton: {
                                left: 0, top: 0, width: 140, height: 30,
                                text: 'Back',
                                onClick: this.handleBackToConfigurationButtonClick
                            },
                            traitPointsAvailableLabel: {
                                left: 150, top: 0, width: 100, height: 30,
                                text: 'Trait Points: 0 / 0'
                            },
                            availableTraitsPanel: {
                                left: 0, top: 40, right: 0, bottom: 0,
                                controls: {}
                            }
                        }
                    },
                    chatTextBox: {
                        bottom: 35, height: 25, left: 0, right: 0,
                        onKeyDown: this.handleChatTextBoxKeyDown,
                        placeholderText: 'Chat - Type messages here and press enter.'
                    }
                }
            }
        }

        public root: UI.UIControl = null;

        constructor() {
            this.root = UI.compile(this.layout)[0];
        }

        show() {

            // Reset spent trait points
            traitSetup.availablePoints = 0;
            traitSetup.spentPoints = 0;
            traitSetup.names = [];

            // Get list of all available traits
            var traits: Array<TraitEffect> = [];
            var allEffects = Effects.create();
            for (var i = 0; i < allEffects.available.length; i++) {
                var effect = allEffects.available[i];
                if (effect.category == EffectCategory.trait) traits.push(<TraitEffect>effect);
            }

            // Make all available traits selectable
            var panel = UI.getControlByName<UI.Panel>(this.root, 'availableTraitsPanel');
            panel.controls = [];
            for (var i = 0; i < traits.length; i++) {
                var trait = <TraitEffect>traits[i];
                var checkBox = new UI.CheckBox({ left: 0, top: i * 32, width: 450, height: 24, trait: trait });
                checkBox.text = '[' + trait.pointsRequired + '] ' + trait.name + ' (' + trait.helpText[0] + ')';
                checkBox.onChecked = this.handleTraitCheckBoxChecked;
                checkBox.onUnchecked = this.handleTraitCheckBoxUnchecked;
                panel.controls.push(checkBox);
            }
            UI.compute(UI.root, UI.Bounds.create(canvas));

            this.updatePlayerList();
            channel.subscribe('onPlayerJoined', this.handlePlayerJoined);
            channel.subscribe('onPlayerListSupplied', this.handlePlayerListSupplied);
            channel.subscribe('onPlayerDisconnected', this.handlePlayerDisconnected);
            channel.subscribe('onReceiveAvailableGenerators', this.handleReceiveAvailableGenerators);
            channel.subscribe('onReceiveAvailableGalaxySizes', this.handleReceiveAvailableGalaxySizes);
            channel.subscribe('onReceiveAvailableResources', this.handleReceiveAvailableResources);
            channel.subscribe('onReceiveAvailableTraits', this.handleReceiveAvailableTraits);
            channel.subscribe('onChangeMultiplayerConfig', this.handleConfigurationSupplied);
            channel.subscribe('onPlayerReady', this.handlePlayerReady);
            channel.subscribe('onPlayerNotReady', this.handlePlayerNotReady);
            UI.getControlByName(UI.root, 'specifyNamePanel').visible = true;
            UI.getControlByName(UI.root, 'configurationPanel').visible = false;
            UI.getControlByName(UI.root, 'traitsPanel').visible = false;
            UI.getControlByName(UI.root, 'chatTextBox').visible = false;
            var name = localStorage.getItem('name');
            UI.getControlByName<UI.TextBox>(UI.root, 'nameTextBox').text = name === null ? 'Admiral' : name;
            if (TEST_MODE) this.handleJoinButtonClick(null, null);
        }

        hide() {

            // Clear chat
            Notices.clearMessages();

            // Unsubscribe to channel events
            channel.unsubscribe('onPlayerJoined', this.handlePlayerJoined);
            channel.unsubscribe('onPlayerListSupplied', this.handlePlayerListSupplied);
            channel.unsubscribe('onPlayerDisconnected', this.handlePlayerDisconnected);
            channel.unsubscribe('onReceiveAvailableGenerators', this.handleReceiveAvailableGenerators);
            channel.unsubscribe('onReceiveAvailableGalaxySizes', this.handleReceiveAvailableGalaxySizes);
            channel.unsubscribe('onReceiveAvailableResources', this.handleReceiveAvailableResources);
            channel.unsubscribe('onReceiveAvailableTraits', this.handleReceiveAvailableTraits);
            channel.unsubscribe('onChangeMultiplayerConfig', this.handleConfigurationSupplied);
            channel.unsubscribe('onPlayerReady', this.handlePlayerReady);
            channel.unsubscribe('onPlayerNotReady', this.handlePlayerNotReady);
        }

        updatePlayerList() {
            for (var playerNumber = 1; playerNumber <= 8; playerNumber++) {
                var labelName = 'player' + playerNumber + 'Label';
                UI.getControlByName<UI.Label>(UI.root, labelName).text = 'Player ' + playerNumber + ': Not connected';
            }
            for (var i in channel.players) {
                var player = channel.players[i];
                var playerNumber = parseInt(i) + 1;
                var labelName = 'player' + playerNumber + 'Label';
                var labelText = 'Player ' + playerNumber + ': ' + player.name + ' (' + (player.state == 'ready' ? 'READY' : 'NOT READY') + ')';
                UI.getControlByName<UI.Label>(UI.root, labelName).text = labelText;
            }
        }

        handleJoinButtonClick(sender, e) {
            var name = UI.getControlByName<UI.TextBox>(UI.root, 'nameTextBox').text;
            channel.invoke.joinGame(name);
            UI.getControlByName(UI.root, 'specifyNamePanel').visible = false;
            UI.getControlByName(UI.root, 'configurationPanel').visible = true;
            UI.getControlByName(UI.root, 'readyButton').enabled = true;
            UI.getControlByName(UI.root, 'notReadyButton').enabled = false;
        }

        askForReplaysButtonClick(sender, e) {
            channel.invoke.enterReplaySelection();
        }

        handleConfigurationChanged() {
            var generator = UI.getControlByName<UI.ComboBox>(UI.root, 'generatorComboBox').selectedIndex;
            var galaxySize = UI.getControlByName<UI.ComboBox>(UI.root, 'galaxySizeComboBox').selectedIndex;
            var resources = UI.getControlByName<UI.ComboBox>(UI.root, 'resourcesComboBox').selectedIndex;
            var traitsComboBox = UI.getControlByName<UI.ComboBox>(UI.root, 'traitsComboBox');
            var goodies = UI.getControlByName<UI.CheckBox>(UI.root, 'goodiesCheckBox').isChecked;
            var wrecks = UI.getControlByName<UI.CheckBox>(UI.root, 'wrecksCheckBox').isChecked;
            lobbyUI.updateTraitPoints();
            channel.invoke.configureMultiplayer(generator, galaxySize, resources, traitsComboBox.selectedIndex, goodies, wrecks);
        }

        handleReceiveAvailableGenerators(descriptions: Array<string>) {
            var comboBox = UI.getControlByName<UI.ComboBox>(UI.root, 'generatorComboBox');
            comboBox.items = [];
            for (var i in descriptions) {
                comboBox.items.push(new UI.ListBoxItem(descriptions[i]));
            }
        }

        handleReceiveAvailableGalaxySizes(descriptions: Array<string>) {
            var comboBox = UI.getControlByName<UI.ComboBox>(UI.root, 'galaxySizeComboBox');
            comboBox.items = [];
            for (var i in descriptions) {
                comboBox.items.push(new UI.ListBoxItem(descriptions[i]));
            }
        }

        handleReceiveAvailableResources(descriptions: Array<string>) {
            var comboBox = UI.getControlByName<UI.ComboBox>(UI.root, 'resourcesComboBox');
            comboBox.items = [];
            for (var i in descriptions) {
                comboBox.items.push(new UI.ListBoxItem(descriptions[i]));
            }
        }

        handleReceiveAvailableTraits(traits: Array<{ description: string; points: number }>) {
            var comboBox = UI.getControlByName<UI.ComboBox>(UI.root, 'traitsComboBox');
            comboBox.items = [];
            for (var i = 0; i < traits.length; i++) {
                var trait = traits[i];
                var listBoxItem = new UI.ListBoxItem(trait.description);
                listBoxItem['traitPoints'] = trait.points;
                comboBox.items.push(listBoxItem);
            }
        }

        handleConfigurationSupplied(generator: number, galaxySize: number, resources: number, traits: number, goodies: boolean, wrecks: boolean) {
            UI.getControlByName<UI.ComboBox>(UI.root, 'generatorComboBox').selectedIndex = generator;
            UI.getControlByName<UI.ComboBox>(UI.root, 'galaxySizeComboBox').selectedIndex = galaxySize;
            UI.getControlByName<UI.ComboBox>(UI.root, 'resourcesComboBox').selectedIndex = resources;
            UI.getControlByName<UI.ComboBox>(UI.root, 'traitsComboBox').selectedIndex = traits;
            UI.getControlByName<UI.CheckBox>(UI.root, 'goodiesCheckBox').isChecked = goodies;
            UI.getControlByName<UI.CheckBox>(UI.root, 'wrecksCheckBox').isChecked = wrecks;
            lobbyUI.handleNotReadyButtonClick(null, null);
            lobbyUI.updateTraitPoints();
        }

        updateTraitPoints() {

            // Update trait points available
            var traitsComboBox = UI.getControlByName<UI.ComboBox>(UI.root, 'traitsComboBox');
            var traitItem = traitsComboBox.items[traitsComboBox.selectedIndex];
            traitSetup.availablePoints = traitItem['traitPoints'];
            UI.getControlByName<UI.CheckBox>(UI.root, 'selectTraitsButton').enabled = traitSetup.availablePoints > 0;
            UI.getControlByName<UI.Label>(UI.root, 'traitPointsAvailableLabel').text = 'Trait Points: ' + traitSetup.spentPoints + ' / ' + traitSetup.availablePoints;
        }

        handleBackToConfigurationButtonClick(sender, e) {
            UI.getControlByName(UI.root, 'configurationPanel').visible = true;
            UI.getControlByName(UI.root, 'traitsPanel').visible = false;
        }

        handleSelectTraitsButtonClicked(sender, e) {
            UI.getControlByName(UI.root, 'configurationPanel').visible = false;
            UI.getControlByName(UI.root, 'traitsPanel').visible = true;
            lobbyUI.updateTraitPoints();
        }

        handleTraitCheckBoxChecked(sender: UI.CheckBox, e) {
            var trait = <TraitEffect>sender['trait'];
            if (traitSetup.spentPoints + trait.pointsRequired > traitSetup.availablePoints) {
                Notices.addMessage(MessageType.fatal, 'You do not have enough trait points available to purchase "' + trait.name + '".');
            }
            traitSetup.spentPoints += trait.pointsRequired;
            traitSetup.names.push(trait.name);
            lobbyUI.updateTraitPoints();
        }

        handleTraitCheckBoxUnchecked(sender: UI.CheckBox, e) {
            var trait = <TraitEffect>sender['trait'];
            traitSetup.spentPoints -= trait.pointsRequired;
            traitSetup.names.splice(traitSetup.names.indexOf(trait.name), 1);
            lobbyUI.updateTraitPoints();
        }

        handleReadyButtonClick(sender, e) {

            // Do spent trait points add up properly?
            if (traitSetup.spentPoints > traitSetup.availablePoints) {
                Notices.addMessage(MessageType.fatal, 'You have spent too many trait points. Please change your trait selections.');
                return;
            }

            // Set ready state
            channel.invoke.ready();
            UI.getControlByName(UI.root, 'readyButton').enabled = false;
            UI.getControlByName(UI.root, 'notReadyButton').enabled = true;
            UI.getControlByName(UI.root, 'generatorComboBox').enabled = false;
            UI.getControlByName(UI.root, 'galaxySizeComboBox').enabled = false;
            UI.getControlByName(UI.root, 'resourcesComboBox').enabled = false;
            UI.getControlByName(UI.root, 'traitsComboBox').enabled = false;
            UI.getControlByName(UI.root, 'selectTraitsButton').enabled = false;
            UI.getControlByName(UI.root, 'goodiesCheckBox').enabled = false;
            UI.getControlByName(UI.root, 'wrecksCheckBox').enabled = false;
        }

        handleNotReadyButtonClick(sender, e) {
            if (UI.getControlByName(UI.root, 'notReadyButton').enabled == true) {
                channel.invoke.notReady();
            }
            UI.getControlByName(UI.root, 'readyButton').enabled = true;
            UI.getControlByName(UI.root, 'notReadyButton').enabled = false;
            UI.getControlByName(UI.root, 'generatorComboBox').enabled = true;
            UI.getControlByName(UI.root, 'galaxySizeComboBox').enabled = true;
            UI.getControlByName(UI.root, 'resourcesComboBox').enabled = true;
            UI.getControlByName(UI.root, 'traitsComboBox').enabled = true;
            lobbyUI.updateTraitPoints();
            UI.getControlByName(UI.root, 'goodiesCheckBox').enabled = true;
            UI.getControlByName(UI.root, 'wrecksCheckBox').enabled = true;
        }

        handleChatTextBoxKeyDown(sender: UI.UIControl, e: UI.InputArgs) {
            var chatTextBox = UI.getControlByName<UI.TextBox>(UI.root, 'chatTextBox');
            var text = chatTextBox.text.trim();
            if (channel.online && e.key == 'Enter' && text != '') {
                if (text[0] == '/') {
                    if (text.length > 1) channel.invoke.admin(text.substring(1));
                } else {
                    channel.invoke.chat(channel.playerName + ': ' + text);
                }                
                chatTextBox.text = '';
            }
        }

        handleDisconnectButtonClick(sender, e) {
            channel.disconnect();
            resetToMainMenu();
        }

        handlePlayerListSupplied(players) {
            lobbyUI.updatePlayerList();
        }

        handlePlayerJoined(player: Player) {
            lobbyUI.updatePlayerList();
            var name = UI.getControlByName<UI.TextBox>(UI.root, 'nameTextBox').text;
            localStorage.setItem('name', name);
            if (player.code == channel.playerCode) {
                UI.getControlByName<UI.TextBox>(UI.root, 'chatTextBox').visible = true;
            } else {
                Notices.addMessage(MessageType.fromServer, player.name + ' joined the game.');
            }
            lobbyUI.handleNotReadyButtonClick(null, null);
        }

        handlePlayerReady(player) {
            lobbyUI.updatePlayerList();
        }

        handlePlayerNotReady(player) {
            lobbyUI.updatePlayerList();
        }

        handlePlayerDisconnected(player) {
            lobbyUI.updatePlayerList();
            lobbyUI.handleNotReadyButtonClick(null, null);
        }

    }

}